package com.example.cas;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 题目：实现一个自旋锁
 * 自旋锁好处：循环比较获取没有类似wait的阻塞。
 * <p>
 * 通过CAS操作完成自旋锁，A线程先进来调用myLock方法自己持有锁5秒钟，B随后进来后发现
 * 当前有线程持有锁，不是null，所以只能通过自旋等待，直到A释放锁后B随后抢到。
 */
@Slf4j
public class SpinLockDemo {
    // 原子引用Thread
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();

        new Thread(() -> {
            spinLockDemo.MyLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                log.error("Exception:", e.fillInStackTrace());
            }
            spinLockDemo.MyUnLock();
        }, "t1").start();

        new Thread(() -> {
            spinLockDemo.MyLock();
            spinLockDemo.MyUnLock();
        }, "t2").start();
    }

    /**
     * 加锁
     * ABA问题
     * 空自旋  锁饥饿
     */
    public void MyLock() {
        log.info("{}---come in", Thread.currentThread().getName());
        while (!atomicReference.compareAndSet(null, Thread.currentThread())) {
        }
        log.info("{}---持有锁成功", Thread.currentThread().getName());
    }

    /**
     * 释放锁
     */
    public void MyUnLock() {
        atomicReference.compareAndSet(Thread.currentThread(), null);
        log.info("{}---释放锁成功", Thread.currentThread().getName());
    }
}
